package llmweb2api

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"log"
	"net/http"
	"sync"
	"time"

	"container/list"

	"github.com/google/uuid"
)

// 任务结构体
type Job struct {
	Server      *Server    `json:"-"`
	ID          string     `json:"id"`
	Question    string     `json:"question"`
	Answer      string     `json:"answer"`
	Status      string     `json:"status"` // pending, completed
	CreatedAt   time.Time  `json:"created_at"`
	CompletedAt time.Time  `json:"completed_at,omitempty"`
	Timeout     int64      `json:"timeout"` // 大于0时，任务会主动超时并再次被投递
	Callback    func(*Job) `json:"-"`
}

// 任务列表响应
type JobListResponse struct {
	AfterTime int64    `json:"after_time"` // 下次获取任务列表的时间戳
	List      []string `json:"list"`       // 任务ID列表
}

// 问题响应
type QuestionResponse struct {
	Question string   `json:"question"`
	Options  *Options `json:"options"`
}

// 答案请求
type AnswerRequest struct {
	Message string `json:"message"`
}

func (s *Server) initJobs(maxWorkers int) {
	s.runningWorkers = make(chan struct{}, maxWorkers)
}

// 任务投递
func (job *Job) Deliver() {
	job.Server.runningWorkers <- struct{}{}
	job.Server.processingJobs <- job

	job.Server.publishMutex.Lock()
	job.Server.jobs[job.ID] = job
	job.Timeout = time.Now().Add(time.Duration(job.Server.opts.TimeoutMs) * time.Millisecond).Unix()
	if job.Server.expireJobs[job.Timeout] == nil {
		job.Server.expireJobs[job.Timeout] = &list.List{}
	}
	job.Server.expireJobs[job.Timeout].PushBack(job)
	job.Server.publishMutex.Unlock()
}

// 任务完成要及时调用Done进行销毁
func (job *Job) Done(answer string) {
	<-job.Server.runningWorkers
	job.Answer = answer
	job.Status = "completed"
	job.CompletedAt = time.Now()
	go func() {
		defer delete(job.Server.jobs, job.ID)
		job.Callback(job)
	}()
}

// 新建任务
func (s *Server) NewJob(question string, callback func(*Job)) *Job {
	job := &Job{
		Server:    s,
		ID:        uuid.New().String(),
		Question:  question,
		Status:    "pending",
		CreatedAt: time.Now(),
		Callback:  callback,
	}
	return job
}

// 获取任务ID列表
func (s *Server) GetJobList() []string {
	jobIds := []string{}

	for {
		select {
		case job := <-s.processingJobs:
			jobIds = append(jobIds, job.ID)
		default:
			// 没有更多任务时直接返回
			return jobIds
		}
	}
}

type Options struct {
	QuietMs    int    `json:"quietMs"`
	TimeoutMs  int    `json:"timeoutMs"`
	Address    string `json:"address"`
	MaxWorkers int    `json:"maxWorkers"`
	Logger     *log.Logger
}

// 根据任务ID获取问题
func (s *Server) GetQuestion(taskID string) (questionResponse *QuestionResponse) {
	questionResponse = &QuestionResponse{
		Question: "",
		Options:  s.opts,
	}

	if taskID == "" {
		return
	}

	job, exists := s.jobs[taskID]
	if !exists {
		return
	}
	if job.Status == "completed" {
		return
	}

	questionResponse.Question = job.Question
	return
}

// 根据任务ID设置答案
func (s *Server) SetAnswer(taskID string, answer string) bool {
	job, exists := s.jobs[taskID]
	if !exists {
		return false
	}

	job.Done(answer)
	return true
}

// 响应写入器包装器，用于捕获响应内容
type responseWriter struct {
	http.ResponseWriter
	statusCode int
	body       *bytes.Buffer
}

func (rw *responseWriter) WriteHeader(code int) {
	rw.statusCode = code
	rw.ResponseWriter.WriteHeader(code)
}

func (rw *responseWriter) Write(b []byte) (int, error) {
	rw.body.Write(b)
	return rw.ResponseWriter.Write(b)
}

// 日志中间件
func logMiddleware(next http.HandlerFunc) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		start := time.Now()

		// 读取请求体
		var requestBody []byte
		if r.Method == "POST" {
			requestBody, _ = io.ReadAll(r.Body)
			r.Body = io.NopCloser(bytes.NewBuffer(requestBody))
		}

		// 包装响应写入器
		rw := &responseWriter{
			ResponseWriter: w,
			statusCode:     200,
			body:           &bytes.Buffer{},
		}

		// 打印请求日志
		log.Printf("=== API请求日志 ===\n")
		log.Printf("时间: %s\n", time.Now().Format("2006-01-02 15:04:05"))
		log.Printf("方法: %s\n", r.Method)
		log.Printf("路径: %s\n", r.URL.Path)
		log.Printf("查询参数: %s\n", r.URL.RawQuery)
		if len(requestBody) > 0 {
			log.Printf("请求体: %s\n", string(requestBody))
		}
		log.Printf("状态码: %d\n", rw.statusCode)
		log.Printf("响应体: %s\n", rw.body.String())
		log.Printf("耗时: %v\n", time.Since(start))

		// 调用原始处理器
		next(rw, r)

		log.Printf("==================\n\n")
	}
}

type Server struct {
	opts           *Options
	jobs           map[string]*Job
	expireJobs     map[int64]*list.List
	processingJobs chan *Job
	publishMutex   *sync.Mutex
	runningWorkers chan struct{}
}

func NewServer(opts *Options) *Server {
	var options = Options{
		QuietMs:    2000,
		TimeoutMs:  900000,
		Address:    "http://localhost:8123",
		MaxWorkers: 10,
		Logger:     log.Default(),
	}
	if opts != nil {
		if opts.Address != "" {
			options.Address = opts.Address
		}
		if opts.MaxWorkers != 0 {
			options.MaxWorkers = opts.MaxWorkers
		}
		if opts.QuietMs != 0 {
			options.QuietMs = opts.QuietMs
		}
		if opts.TimeoutMs != 0 {
			options.TimeoutMs = opts.TimeoutMs
		}
		if opts.Logger != nil {
			log.SetFlags(opts.Logger.Flags())
			log.SetOutput(opts.Logger.Writer())
			log.SetPrefix(opts.Logger.Prefix())
		}
	}
	server := &Server{
		opts:           &options,
		jobs:           make(map[string]*Job),
		expireJobs:     make(map[int64]*list.List),
		processingJobs: make(chan *Job, 100000),
		publishMutex:   &sync.Mutex{},
		runningWorkers: make(chan struct{}, options.MaxWorkers),
	}
	server.initJobs(options.MaxWorkers)
	return server
}

func (s *Server) Start() {
	// 控制台日志重定向到文件
	address := s.opts.Address
	http.HandleFunc("/question", logMiddleware(func(w http.ResponseWriter, r *http.Request) {
		taskID := r.URL.Query().Get("taskID")
		response := s.GetQuestion(taskID)
		json.NewEncoder(w).Encode(response)
	}))
	log.Println("GET ", fmt.Sprintf("%s/question?taskID=\n", address))
	log.Println("--------------------------------")

	http.HandleFunc("/answer", logMiddleware(func(w http.ResponseWriter, r *http.Request) {
		taskID := r.URL.Query().Get("taskID")
		body, err := io.ReadAll(r.Body)
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		var answer AnswerRequest
		json.Unmarshal(body, &answer)
		result := s.SetAnswer(taskID, answer.Message)
		json.NewEncoder(w).Encode(result)
	}))
	log.Println("POST ", fmt.Sprintf("%s/answer?taskID=", address))
	log.Println("body: {message: answer_r}")
	log.Println("--------------------------------")

	http.HandleFunc("/questions", logMiddleware(func(w http.ResponseWriter, r *http.Request) {
		response := s.GetJobList()
		json.NewEncoder(w).Encode(response)
	}))
	log.Println("GET ", fmt.Sprintf("%s/questions", address))

	go s.monitorExpireJobs()
	http.ListenAndServe(address, nil)
}

// 监控过期的任务，重新加入到任务列表中
func (s *Server) monitorExpireJobs() {
	for {
		time.Sleep(1 * time.Second)
		now := time.Now().Unix()
		if s.expireJobs[now] == nil {
			continue
		}

		go func() {
			for e := s.expireJobs[now].Front(); e != nil; e = e.Next() {
				job := e.Value.(*Job)
				if job.Status == "completed" {
					continue
				}
				<-s.runningWorkers
				job.Deliver()
				log.Printf("任务%s已重新加入到任务列表中", job.ID)
			}
			delete(s.expireJobs, now)
		}()
	}
}
